package com.dinzeer.sjapadder.se;

import com.dinzeer.legendreliclib.lib.util.slashblade.SlashBladeUtil;
import com.dinzeer.sjapadder.Config;
import com.dinzeer.sjapadder.register.SjaSpecialEffectRegsitry;
import mods.flammpfeil.slashblade.capability.slashblade.ISlashBladeState;
import mods.flammpfeil.slashblade.data.tag.SlashBladeEntityTypeTagProvider;
import mods.flammpfeil.slashblade.item.ItemSlashBlade;
import mods.flammpfeil.slashblade.registry.SpecialEffectsRegistry;
import mods.flammpfeil.slashblade.registry.specialeffects.SpecialEffect;
import mods.flammpfeil.slashblade.util.AttackManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.joml.Vector3f;

import java.util.List;
import java.util.function.Predicate;

@Mod.EventBusSubscriber
public class ShadowOfRevenant extends SpecialEffect {

    public static final String SHADOW_OF_REVENANT = "slashblade_shadow_of_revenant";
    public static final String REVENANT_1 = "revenant_1";
    public static final String REVENANT_2 = "revenant_2";
    public static final String REVENANT_3 = "revenant_3";

    public static final String[] REVENANT_KEYS = {
            REVENANT_1, REVENANT_2, REVENANT_3
    };

    protected static int RADIUS = 12;
    protected static int HEIGHT = 4;
    protected static int[] defaultValues = {0, 2, 4};

    protected static int PARTICLE_DENSITY = 48;

    public static final Vector3f COLOR_RED = new Vector3f(0.5f, 0f, 0f);
    protected static final DustParticleOptions PARTICLE_RED = new DustParticleOptions(COLOR_RED, 0.5F);

    protected static final Predicate<LivingEntity> VALID_ENTITY = entity -> {
        return entity.isAlive() && !entity.getType().is(SlashBladeEntityTypeTagProvider.EntityTypeTags.ATTACKABLE_BLACKLIST);
    };

    protected static AABB getArea(BlockPos blockPos) {
        return new AABB(
                blockPos.offset(-RADIUS, -HEIGHT, -RADIUS),
                blockPos.offset(RADIUS, HEIGHT, RADIUS)
        );
    }

    public ShadowOfRevenant() {
        super(35);
    }

    @SubscribeEvent
    public static void onLivingTick(LivingEvent.LivingTickEvent event) {
        LivingEntity owner = event.getEntity();
        if (owner.tickCount % 20 == 5) {
            if (owner.level() instanceof ServerLevel serverLevel) {
                ItemStack bladeStack = owner.getMainHandItem();
                if (bladeStack.getItem() instanceof ItemSlashBlade) {
                    ISlashBladeState state = SlashBladeUtil.getState(bladeStack);
                    List<ResourceLocation> effects = state.getSpecialEffects();
                    for (ResourceLocation effectId : effects) {
                        SpecialEffect effect = SpecialEffectsRegistry.REGISTRY.get().getValue(effectId);
                        if (effect instanceof ShadowOfRevenant shadowOfRevenant) {
                            shadowOfRevenant.handleEffect(serverLevel, owner, bladeStack, state);
                            break;
                        }
                    }
                }
            }
        }
    }

    private void handleEffect(ServerLevel level, LivingEntity attacker, ItemStack bladeStack, ISlashBladeState state) {
        if (attacker instanceof ServerPlayer player) {
            if (!SpecialEffect.isEffective(SjaSpecialEffectRegsitry.SHADOW_OF_REVENANT.get(), player.experienceLevel))
                return;
        }
        CompoundTag nbt = bladeStack.getOrCreateTag();
        if (!nbt.contains(SHADOW_OF_REVENANT)) {
            nbt.put(SHADOW_OF_REVENANT, new CompoundTag());
        }
        CompoundTag shadowOfRevenantTag = nbt.getCompound(SHADOW_OF_REVENANT);

        int[] revenantValues = new int[3];

        for (int i = 0; i < 3; i++) {
            if (!shadowOfRevenantTag.contains(REVENANT_KEYS[i])) {
                revenantValues[i] = defaultValues[i];
                shadowOfRevenantTag.putInt(REVENANT_KEYS[i], revenantValues[i]);
            } else {
                revenantValues[i] = Math.min(5, shadowOfRevenantTag.getInt(REVENANT_KEYS[i]) + 1);
                shadowOfRevenantTag.putInt(REVENANT_KEYS[i], revenantValues[i]);
            }

            if (revenantValues[i] >= 5) {
                Entity mainTarget = state.getTargetEntity(level);
                if (mainTarget instanceof LivingEntity living && living.isAlive() && living.getHealth() > 0) {
                    doRevenantAttack(level, attacker, living);
                    shadowOfRevenantTag.putInt(REVENANT_KEYS[i], level.getRandom().nextInt(3));
                } else {
                    List<LivingEntity> list = level.getEntitiesOfClass(LivingEntity.class, getArea(attacker.getOnPos()), VALID_ENTITY);
                    int k = 0;
                    while (k < list.size()) {
                        LivingEntity target = list.get(k);
                        if (!target.isAlive() || target.getHealth() <= 0 || target == attacker) {
                            k++;
                        } else {
                            doRevenantAttack(level, attacker, target);
                            shadowOfRevenantTag.putInt(REVENANT_KEYS[i], level.getRandom().nextInt(2));
                            break;
                        }
                    }
                }

            }

        }
    }

    private void doRevenantAttack(ServerLevel level, LivingEntity attacker, LivingEntity target) {
        drawAttackParticles(level, attacker.getOnPos().above(), target.getOnPos().above());
        AttackManager.doMeleeAttack(attacker, target, true, false, Config.shadowOfRevenantRatio);
        target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 10, 4));
    }

    private void drawAttackParticles(ServerLevel level, BlockPos pos1, BlockPos pos2) {
        double dx = pos2.getX() - pos1.getX();
        double dy = pos2.getY() - pos1.getY();
        double dz = pos2.getZ() - pos1.getZ();

        for (int i = 0; i <= PARTICLE_DENSITY; i++) {
            double t = i / (double) PARTICLE_DENSITY;
            double x = pos1.getX() + 0.5 + dx * t;
            double y = pos1.getY() + 0.5 + dy * t;
            double z = pos1.getZ() + 0.5 + dz * t;

            level.sendParticles(
                    PARTICLE_RED,
                    x, y, z,
                    1,
                    0.0d, 0.0d, 0.0d,
                    1.0d
            );
        }
    }

}
